package com.parent.utils;

import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.parent.elasticsearch.old.ElasticsearchR;
import com.parent.elasticsearch.old.esentitys.HitsNew1;

import java.lang.reflect.Field;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @Author yan
 * @Date 2023/7/19 0019 15:41
 * @Description
 */
public class ElasticsechToEntityUtils {
    /**
     * @param elasticsearchResult es返回的字符串
     * @param idFildeName         对象需要设置的字段名--（id设置）
     * @param toClass             需要转换成的对象类型
     * @param <T>
     * @return
     */
    public static <T> List<T> elasticsearchToList(String elasticsearchResult, String idFildeName, Class<T> toClass) {
        ElasticsearchR elasticsearchR = JSONUtil.toBean(elasticsearchResult, ElasticsearchR.class);
//        System.out.println("======");
//        System.out.println(elasticsearchR);
//        System.out.println("======");
        List<HitsNew1> hits = elasticsearchR.getHits().getHits();
        List<T> list = hits.stream().map(v -> getOne(idFildeName, toClass, v)).collect(Collectors.toList());
        return list;
    }

    /**
     * @param elasticsearchResult es返回的字符串
     * @param idFildeName         对象需要设置的字段名--（id设置）
     * @param toClass             需要转换成的对象类型
     * @param <T>
     * @return
     */
    public static <T> T elasticsearchToOne(String elasticsearchResult, String idFildeName, Class<T> toClass) {
        ElasticsearchR elasticsearchR = JSONUtil.toBean(elasticsearchResult, ElasticsearchR.class);
        List<HitsNew1> hits = elasticsearchR.getHits().getHits();
        T t = hits.stream().map(v -> getOne(idFildeName, toClass, v)).findFirst().get();
        return t;
    }

    /**
     * @param elasticsearchResult es返回的字符串
     * @param idFildeName         对象需要设置的字段名--（id设置）
     * @param toClass             需要转换成的对象类型
     * @param <T>
     * @return
     */
    public static <T> List<T> elasticsearchToListAndId(String elasticsearchResult, String idFildeName, Class<T> toClass) {
        ElasticsearchR elasticsearchR = JSONUtil.toBean(elasticsearchResult, ElasticsearchR.class);
//        System.out.println("======");
//        System.out.println(elasticsearchR);
//        System.out.println("======");
        List<HitsNew1> hits = elasticsearchR.getHits().getHits();
        List<T> list = hits.stream().map(v -> getOneAndId(idFildeName, toClass, v)).collect(Collectors.toList());
        return list;
    }

    /**
     * @param elasticsearchResult es返回的字符串
     * @param idFildeName         对象需要设置的字段名--（id设置）
     * @param toClass             需要转换成的对象类型
     * @param <T>
     * @return
     */
    public static <T> T elasticsearchToOneAndId(String elasticsearchResult, String idFildeName, Class<T> toClass) {
        ElasticsearchR elasticsearchR = JSONUtil.toBean(elasticsearchResult, ElasticsearchR.class);
        List<HitsNew1> hits = elasticsearchR.getHits().getHits();
        T t = hits.stream().map(v -> getOneAndId(idFildeName, toClass, v)).findFirst().get();
        return t;
    }

    private static <T> T getOne(String idFildeName, Class<T> toClass, HitsNew1 hitsNew) {
        JSONObject entries = JSONUtil.parseObj(hitsNew.get_source());

        T one = JSONUtil.toBean(entries.toString(), toClass);
        return one;
    }

    private static <T> T getOneAndId(String idFildeName, Class<T> toClass, HitsNew1 hitsNew) {
        JSONObject entries = JSONUtil.parseObj(hitsNew.get_source());

        T one = JSONUtil.toBean(entries.toString(), toClass);
        String id = hitsNew.get_id();
        try {
            Class<?> type = one.getClass().getDeclaredField(idFildeName).getType();
            Object o = stringToClass(id, type);

            // 获取 Class 对象
            Class<?> clazz = one.getClass();
            // 获取指定字段的 Field 对象
            Field idField = clazz.getDeclaredField(idFildeName);
            // 设置可访问性，因为可能是私有字段
            idField.setAccessible(true);

            if (type.equals(Long.class)) {
                idField.set(one, (Long) o);
            } else if (type.equals(Integer.class)) {
                idField.set(one, (Integer) o);
            } else {
                idField.set(one, o);
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return one;
    }

    public static <T> T stringToClass(String id, Class<T> tClass) throws IllegalArgumentException, InstantiationException, IllegalAccessException {
        if (tClass.equals(Integer.class)) {
            try {
                return tClass.getConstructor(int.class).newInstance(Integer.parseInt(id));
            } catch (Exception e) {
                throw new IllegalArgumentException("Unable to parse integer from id: " + id);
            }
        } else if (tClass.equals(Long.class)) {
            try {
                return tClass.getConstructor(long.class).newInstance(Long.parseLong(id));
            } catch (Exception e) {
                throw new IllegalArgumentException("Unable to parse long from id: " + id);
            }
        } else if (tClass.equals(String.class)) {
            return (T) id;
        } else {
            throw new IllegalArgumentException("Unsupported id class: " + tClass.getName());
        }
    }
}